﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Google.GData.Documents;
using Google.GData.Client;
using System.IO;
using Microsoft.Win32;
using System.Windows.Forms;
using System.Net;

namespace DocListUploader
{
    class FileUploader
    {
        //The parent form to this one.
        public HiddenForm mainForm;
        public string nextfile = null;
        System.Windows.Forms.ListBox listBox;
        TextBox currUpload;
        TextBox byteCounter;
        ProgressBar progressBar;

        public FileUploader(System.Windows.Forms.ListBox _listBox, TextBox _currUpload, TextBox _byteCounter, ProgressBar _progressBar)
        {
            listBox = _listBox;
            currUpload = _currUpload;
            byteCounter = _byteCounter;
            progressBar = _progressBar;
            
        }

        delegate void MyDelegate(bool show);
        delegate void MyDelegate2(string filename);
        delegate void MyDelegate3(string bytesCounted);
        delegate void MyDelegate4(int percentage);

        string getFileName(string szPath)
        {
            string[] szTokens = szPath.Split('\\');
            return szTokens[szTokens.Length - 1];
        }

        string getFolderName(string szPath)
        {
            string[] szTokens = szPath.Split('\\');
            string ret="";

            for (int i = 0; i < szTokens.Length - 1; i++)
                ret = ret + "_" +szTokens[i];

            return ret;
        }

        private void createFolder( string folder)
        {

            string xml = "<?xml version='1.0' encoding='UTF-8'?><entry xmlns=\"http://www.w3.org/2005/Atom\"><category scheme=\"http://schemas.google.com/g/2005#kind\" term=\"http://schemas.google.com/docs/2007#folder\"/><title>"+folder+"</title></entry>";

            byte[] byteArray = Encoding.ASCII.GetBytes( xml );
            MemoryStream stream = new MemoryStream(byteArray);

            //FileStream fileStream = new FileStream(fileName, FileMode.Open);
            Uri uri = new Uri("http://docs.google.com/feeds/default/private/full");  
              
            mainForm.service.StreamSend( uri, stream, GDataRequestType.Insert, "application/atom+xml", "");
        }


        private void moveDocumentToFolder( string filename, string folder)
        {

            string xml = "<?xml version='1.0' encoding='UTF-8'?><entry xmlns=\"http://www.w3.org/2005/Atom\"><id>https://docs.google.com/feeds/default/private/full/document%3A"+filename+"</id></entry>";

            byte[] byteArray = Encoding.ASCII.GetBytes( xml );
            MemoryStream stream = new MemoryStream(byteArray);

            Uri uri = new Uri("http://docs.google.com/feeds/default/private/full/folder%3A"+folder+"/contents");  
              
            mainForm.service.StreamSend( uri, stream, GDataRequestType.Insert, "application/atom+xml", "");
        }

        private Boolean folderExists(string folder)
        {
            //DocumentsListQuery query = new DocumentsListQuery("https://docs.google.com/feeds/documents/private/full?showfolders=true&title=" + folder);          
            DocumentsListQuery query = new DocumentsListQuery("https://docs.google.com/feeds/documents/private/full/-/folder");          
            
            DocumentsFeed feed = mainForm.service2.Query(query);

            foreach (DocumentEntry entry in feed.Entries)
            {
                if (entry.Title.Text.Equals(folder))
                    return true;
            }

            return false;

        }

        private string getFolderId(string folder)
        {
            DocumentsListQuery query = new DocumentsListQuery("https://docs.google.com/feeds/documents/private/full/-/folder");

            DocumentsFeed feed = mainForm.service2.Query(query);

            foreach (DocumentEntry entry in feed.Entries)
            {
                if (entry.Title.Text.Equals(folder))
                { 
                    //https://docs.google.com/feeds/documents/private/full/folder%3A0B7I2SeEPZGIzYjAxMGJlYWMtN2Q3MS00MWIxLWFkZjktMjdmNGM1ZjUwMDU4}
                    string pt = entry.SelfUri.ToString();
                    string[] szTokens = pt.Split(new string[] { "%3A" }, StringSplitOptions.None );

                    return szTokens[1];
                }
                    
            }

            return "";
        }


        string GetMimeType( string filename)
        {
            FileInfo fileInfo = new FileInfo(filename);

            string mimeType = "application/unknown";

            RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(
                fileInfo.Extension.ToLower()
                );

            if (regKey != null)
            {
                object contentType = regKey.GetValue("Content Type");

                if (contentType != null)
                    mimeType = contentType.ToString();
            }

            return mimeType;
        }

        private string getFileId( string folderId, string filename){
        
            //DocumentsListQuery query = new DocumentsListQuery("https://docs.google.com/feeds/default/private/full/folder%3A"+folderId+"?title=" + filename + "&title-exact=true" );
            DocumentsListQuery query = new DocumentsListQuery("https://docs.google.com/feeds/default/private/full/folder%3A" + folderId + "/contents");
            DocumentsFeed feed = mainForm.service.Query(query);


            foreach (DocumentEntry entry in feed.Entries)
            {
                if (entry.Title.Text.Equals( filename))
                {
                    mainForm.service.Delete( entry);
                    string pt = entry.SelfUri.ToString();
                    string[] szTokens = pt.Split(new string[] { "%3A" }, StringSplitOptions.None);

                    return szTokens[1];
                }

            }

            return null;

        }


        /** private void deleteFile( string fileId)
        {
            Uri uri = new Uri("https://docs.google.com/feeds/default/private/full/"+fileId+"?delete=true");

            mainForm.service.StreamSend(uri, null, GDataRequestType.Delete, null, null);
            mainForm.service.Delete(
        }
         */

        private void setBytesCounted(string bytesCounted)
        {
            byteCounter.Text = bytesCounted;

        }

        private void setProgress(int percentage)
        {
            progressBar.Value = percentage;
        }

        public void actualUploadFile(string folderId, string mimetype, string filename, Stream stream)
        { 
        
            // mainForm.service.
            //Uri uri = new Uri("http://docs.google.com/feeds/default/private/full/folder%3A" + folderId + "/contents/?convert=false");
            string uri = "http://docs.google.com/feeds/default/private/full/folder%3A" + folderId + "/contents/?convert=false";

            HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create( uri);
            httpReq.Method = "POST";
            httpReq.ContentType = mimetype;
            httpReq.UserAgent = "G-DocListUploader/GDataGAuthRequestFactory-CS-Version=1.4.0.2";
            httpReq.Headers.Set("Slug", filename);
            httpReq.Headers.Set("Authorization", "GoogleLogin auth=" + ((GDataGAuthRequestFactory)mainForm.service.RequestFactory).GAuthToken );
            httpReq.Headers.Set("GData-Version", "3.0");
            httpReq.ContentLength = stream.Length;
            //httpReq.Expect = "100-continue";
            //httpReq.Connection = "Close";

            Stream newStream = httpReq.GetRequestStream();

            int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];
            Boolean continueread= true;
            int bytesCounted = 0;
            int percentage = 0;
            while ( continueread)
            {
                int read = stream.Read(buffer, 0, buffer.Length);
                if (read <= 0)
                {
                    continueread = false;
                }
                newStream.Write(buffer, 0, read);

                // update counter
                bytesCounted += read;
                percentage = (int)(bytesCounted * 100 / stream.Length );
                string percentageString = percentage.ToString();
                if (byteCounter.InvokeRequired)
                    byteCounter.Invoke(new MyDelegate3(setBytesCounted), percentageString);
                if (progressBar.InvokeRequired)
                    progressBar.Invoke(new MyDelegate4( setProgress), percentage);
            }

            newStream.Close();            
           
            // 
            // grab te response and print it out to the console along with the status code
            HttpWebResponse response = (HttpWebResponse)httpReq.GetResponse();
            Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
            if ( !response.StatusDescription.Equals("Created"))
                throw new Exception( "Error in upload :" + response.StatusCode);

            //
            byteCounter.Invoke(new MyDelegate3(setBytesCounted), "0");
            progressBar.Invoke(new MyDelegate4(setProgress), 0);
            Logger.log("File succesfully uploaded: " + filename);
        }

        private void uploadFile(string folderfileName)
        {


                // split in filename in filename and folder
                String filename = getFileName(folderfileName);
                String folder = getFolderName(folderfileName);
                String mimetype = GetMimeType(filename);
                try
                {
 
                    //Create Folder
                    if (!(folderExists(folder)))
                        createFolder(folder);

                    String folderId = getFolderId(folder);
                    string fileId = getFileId(folderId, filename);

                    //Upload document in right folder
                    FileStream fileStream = new FileStream( folderfileName, FileMode.Open, FileAccess.Read);
                    Uri uri = new Uri("http://docs.google.com/feeds/default/private/full/folder%3A" + folderId + "/contents/?convert=false");

                    fileStream.Seek(0, 0);
                    actualUploadFile(folderId, mimetype, filename, fileStream);
                    
                    currUpload.Invoke(new MyDelegate2(setFilename), "");
                }
                catch (Exception e)
                {
                    Logger.log("Error uploading document: " + folderfileName + " Message: " + e.Message);
                }
        }


        private void pickNextFile(bool show)
        {
            if (listBox.Items.Count != 0)
            {
                string folderfileName = (string)listBox.Items[0];
                listBox.Items.RemoveAt(0);
                nextfile = folderfileName;
            }
            else
                nextfile = null;
        }

        private void setFilename(string filename)
        {
            currUpload.Text = filename;
        }

        // This method will be called when the thread is started.
        public void DoWork()
        {
            while (!_shouldStop)
            {
                listBox.Invoke(new MyDelegate(pickNextFile), true);
                if (nextfile != null)
                {
                    currUpload.Invoke(new MyDelegate2(setFilename), nextfile);
                    uploadFile(nextfile);
                }
                Thread.Sleep(1000);
            }
        }
        public void RequestStop()
        {
            _shouldStop = true;
        }
        // Volatile is used as hint to the compiler that this data
        // member will be accessed by multiple threads.
        private volatile bool _shouldStop;


    }
}
